#include "triangle.h"
#include "scene.h"
#include <cmath>

Triangle::Triangle()
{
    shared_material= nullptr;
}
//用于计算射线（Ray）与三角形（Triangle）的相交情况，并返回相交的距离
float Triangle::intersect(Ray r) const{
    //计算三角形的边向量 edge1 和 edge2
    Cartesian3 edge1 = verts[1].Point() - verts[0].Point();
    Cartesian3 edge2 = verts[2].Point() - verts[0].Point();

    //Calculate normal
    Cartesian3 normal = edge1.cross(edge2).unit();

    //calculate t
    float t = (verts[0].Point() -r.origin).dot(normal) / r.direction.dot(normal);

    //交点坐标
    Cartesian3 intersectP = r.origin + r.direction * t;

    Cartesian3 edge3 = verts[2].Point() - verts[1].Point();//v2-v3
    Cartesian3 edge4 = verts[0].Point() - verts[2].Point();

    Cartesian3 v1P= intersectP - verts[0].Point();
    Cartesian3 v2P = intersectP - verts[1].Point();
    Cartesian3 v3P = intersectP - verts[2].Point();

    Cartesian3 n1 = edge1.cross(v1P);//edge1(1-2),v1p
    Cartesian3 n2 = edge3.cross(v2P);//edge3(2-3),v2p
    Cartesian3 n3 = edge4.cross(v3P);//edge4(3-1),v3p

    if(n1.dot(n2) >= 0 && n2.dot(n3) >= 0){
        return t;
    }
    else{
        t=-1.0f;
        return t;
    }



}

//Implement barycentric interpolation to obtain the barycentric coordinates at the position of the intersection calculated in the
//previous task.
//实现重心插值，获得上一任务中计算的交点位置的重心坐标。
//bc就是重心坐标barycentric coordinates
Cartesian3 Triangle::baricentric(Cartesian3 o){
    Cartesian3 bc;
    Cartesian3 A = verts[0].Point();
    Cartesian3 B = verts[1].Point();
    Cartesian3 C = verts[2].Point();

    // 计算重心坐标
    float detT = (B - A).cross(C - A).length(); // 三角形面积的两倍

    float alpha = ((B - o).cross(C - o)).length() / detT;
    float beta = ((C - o).cross(A - o)).length() / detT;
    float gamma = 1.0f - alpha - beta;

    bc.x = alpha;
    bc.y = beta;
    bc.z = gamma;

    return bc;
}

Homogeneous4 Triangle::calculateBlinnPhongShading(Homogeneous4 lightPosition,Homogeneous4 lightColor,Cartesian3 barycentricCoords)
{
    // 获取交点坐标
    //Cartesian3 intersectionPoint = r.origin + barycentricCoords.x * verts[0].Point() + barycentricCoords.y * verts[1].Point() + barycentricCoords.z * verts[2].Point();
    Homogeneous4 finalColor(0.0f, 0.0f, 0.0f, 1.0f);

    // Get the material properties of the triangle
    Material* material = shared_material;

    //根据重心坐标和三角形顶点坐标插值计算出三角形内的交点坐标
    Cartesian3 intersectionPoint = barycentricCoords.x * verts[0].Vector() +
                                   barycentricCoords.y * verts[1].Vector() +
                                   barycentricCoords.z * verts[2].Vector();

    //计算过交点的法向量
    Cartesian3 intersectnormal = (normals[0].Vector() * barycentricCoords.x+
                                  normals[1].Vector() * barycentricCoords.y+
                                  normals[2].Vector() * barycentricCoords.z).unit();

    //viewPosition
    Cartesian3 viewPosition(0.0f,0.0f,1.0f);

    //viewDirection,交点坐标指向viewPosition
    Cartesian3 viewDirection=viewPosition - intersectionPoint;

    //lightDirection,交点坐标指向lightPosition
    Cartesian3 lightDirection=lightPosition.Point() - intersectionPoint;

    // 计算Blinn-Phong着色的半程向量
    Cartesian3 halfway = (viewDirection + lightDirection)/2;

    // 使用Lambertian反射模型计算漫反射因子
    float diffuseFactor = 0.0;

    diffuseFactor = std::max(0.0f, intersectnormal.dot(lightDirection));

    // 使用Blinn-Phong反射模型计算镜面反射因子
    float specularFactor = 0.0;

    specularFactor = std::pow(std::max(0.0f, intersectnormal.dot(halfway)), material->shininess);

    //距离衰减（attenuation）
    float attenuation = 1.0f / (1.0f + pow(lightDirection.length(), 2));
    lightColor = lightColor*attenuation;

    Homogeneous4 diffuseColor = lightColor.modulate(material->diffuse)*diffuseFactor;
    Homogeneous4 specularColor = lightColor.modulate(material->specular)*specularFactor;

    finalColor =  diffuseColor + specularColor;
    return finalColor;
    }






